#include "connectionWin.h"

ConnectionWin::ConnectionWin()
{
  delim = ";";  // DEFAULT DELIMITER
  accepting = false;
  connected = false;
  buffer = "";
}

int ConnectionWin::connect(string host, int port)
{
    if (WSAStartup(MAKEWORD(1,1), &wsaData) != 0) {
      //      fprintf(stderr, "WSAStartup failed.\n");
      cerr << "WSAStartup failed" << endl;
      exit(1);
    }

    if ((he=gethostbyname(host.c_str())) == NULL) {  // get the host info 
        perror("gethostbyname");
        exit(1);
    }

    if ((connSock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }

    their_addr.sin_family = AF_INET;    // host byte order 
    their_addr.sin_port = htons(port);  // short, network byte order 
    their_addr.sin_addr = *((struct in_addr *)he->h_addr);
    memset(&(their_addr.sin_zero), '\0', 8);  // zero the rest of the struct 

    if (::connect(connSock, (struct sockaddr *)&their_addr,
		  sizeof(struct sockaddr)) == -1) {
        perror("connect");
        exit(1);
    }
    return RC_OK;
}

string ConnectionWin::read()
{
  string msg;
  //  string delim = ";";
  unsigned int index;

  // CHECK TO SEE IF A MESSAGE IS ALREADY IN THE BUFFER
  // IF SO, RETURN IT
  index = buffer.find(delim, 0);
  if (index != string::npos) {
    msg = buffer.substr(0, index);
    buffer.erase(0, index + delim.length());
    return msg;
  }

  dataLen=recv(connSock, rcvBuff, BUFF_LEN-1, 0);
  if (dataLen < 0) {
    perror("recv");
    exit(1);
  }
  rcvBuff[dataLen] = '\0';
  buffer = buffer + string(rcvBuff);
  index = buffer.find(delim, 0);
  if (index == string::npos) {
    msg = "";
  } else {
    // DON'T RETURN THE DELIMITER AS PART OF THE MESSAGE
    //    msg = buffer.substr(0, index + delim.length());
    msg = buffer.substr(0, index);
    buffer.erase(0, index + delim.length());
  }
  return msg;
}

void ConnectionWin::write(string data)
{
  // USE DEFAULT DELIMITER
  data = data + delim;
  send(connSock, data.c_str(), strlen(data.c_str()), 0);
}

void ConnectionWin::write(string data, string delimParm)
{
  data = data + delimParm;
  send(connSock, data.c_str(), strlen(data.c_str()), 0);
}

void ConnectionWin::close()
{
  shutdown(connSock, 1);
  closesocket(connSock);
  WSACleanup();
}

ConnectionWin ConnectionWin::accept(int port)
{
  ConnectionWin conn;

  if (!accepting) {
    // cout << "ConnectionWin::accept initializing" << endl;
    if (WSAStartup(MAKEWORD(1,1), &wsaData) != 0) {
      cerr << "WSAStartup failed" << endl;
      exit(1);
    }

    yes = 1;
    if ((serverSock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
      perror("socket");
      exit(1);
    }

    if (setsockopt(serverSock, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(int))
	< 0) {
      perror("setsockopt");
      exit(1);
    }
    
    my_addr.sin_family = AF_INET;         // host byte order
    my_addr.sin_port = htons(port);       // short, network byte order
    my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
    memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct

    if (bind(serverSock, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))
	< 0) {
      perror("bind");
      exit(1);
    }
  
    if (listen(serverSock, BACKLOG) <0) {
      perror("listen");
      exit(1);
    }
  }

  // cout << "ConnectionWin::accept about to call accept" << endl;
  sin_size = sizeof(struct sockaddr_in);
  if ((connSock = ::accept(serverSock, (struct sockaddr *)&their_addr, &sin_size))
      == -1) {
    perror("accept");
    exit(1);
  }
  // connected = true; // DON'T WANT TO READ AND WRITE WITH THIS SOCKET
  accepting = true;

  conn.connSock = connSock;
  conn.serverSock = -1;
  conn.connected = true;
  conn.accepting = false;

  // cout << "ConnectionWin::accept about to return" << endl;
  return conn;
}

int ConnectionWin::endAccept()
{
  int rc;
  if (accepting) {
    closesocket(serverSock);
    accepting = false;
  } 
  return RC_OK;
}

string ConnectionWin::readNonblock()
{
  string msg;
  //  string delim = ";";
  unsigned int index;
  dataLen=recv(connSock, rcvBuff, BUFF_LEN-1, 0);
  if (dataLen <= 0 && WSAGetLastError() != WSAEWOULDBLOCK) {
    perror("recv");
    exit(1);
  }
  if (dataLen > 0) {
    rcvBuff[dataLen] = '\0';
    buffer = buffer + string(rcvBuff);
  }
  index = buffer.find(delim, 0);
  if (index == string::npos) {
    msg = "";
  } else {
    // DON'T RETURN THE DELIMITER AS PART OF THE MESSAGE
    //    msg = buffer.substr(0, index + delim.length());
    msg = buffer.substr(0, index);
    buffer.erase(0, index + delim.length());
  }
  return msg;
}

void ConnectionWin::setNonblock()
{
  unsigned long nonblocking = 1;

  if (ioctlsocket(connSock, FIONBIO, &nonblocking) != 0) {
    perror("ioctlsocket");
    exit(1);
  }
}

